package com.chris.easymallware.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.chris.common.RRException;
import com.chris.common.constant.WareConstant;
import com.chris.common.utils.R;
import com.chris.easymallware.dto.MergeDto;
import com.chris.easymallware.dto.PurchaseDetailsDto;
import com.chris.easymallware.dto.PurchaseDoneDto;
import com.chris.easymallware.entity.PurchaseDetailEntity;
import com.chris.easymallware.entity.WareSkuEntity;
import com.chris.easymallware.feign.ProductFeignService;
import com.chris.easymallware.service.PurchaseDetailService;
import com.chris.easymallware.service.WareSkuService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chris.common.utils.PageUtils;
import com.chris.common.utils.Query;

import com.chris.easymallware.dao.PurchaseDao;
import com.chris.easymallware.entity.PurchaseEntity;
import com.chris.easymallware.service.PurchaseService;
import org.springframework.transaction.annotation.Transactional;


@Service("purchaseService")
public class PurchaseServiceImpl extends ServiceImpl<PurchaseDao, PurchaseEntity> implements PurchaseService {

    @Autowired
    private PurchaseDetailService purchaseDetailService;
    @Autowired
    private WareSkuService wareSkuService;
    @Autowired
    private ProductFeignService productFeignService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<PurchaseEntity> page = this.page(
                new Query<PurchaseEntity>().getPage(params),
                new QueryWrapper<PurchaseEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public PageUtils unreceiveList(Map<String, Object> params) {
        IPage<PurchaseEntity> page = this.page(
                new Query<PurchaseEntity>().getPage(params),
                new QueryWrapper<PurchaseEntity>()
                        .lambda()
                        .in(PurchaseEntity::getStatus, new ArrayList<Integer>() {{
                            this.add(0);
                            this.add(1);
                        }})
        );

        return new PageUtils(page);
    }

    @Override
    @Transactional
    public void merge(MergeDto mergeDto) {
        Long purchaseId = mergeDto.getPurchaseId();
        if (purchaseId == null) {
            PurchaseEntity purchaseEntity = new PurchaseEntity();
            purchaseEntity.setStatus(WareConstant.MergeStatusEnum.created.getCode());
            purchaseEntity.setUpdateTime(new Date());
            purchaseEntity.setCreateTime(new Date());
            this.save(purchaseEntity);
            purchaseId = purchaseEntity.getId();
        }
        Long finalPurchaseId = purchaseId;
        Long[] items = mergeDto.getItems();
        long count = purchaseDetailService.count(new LambdaQueryWrapper<PurchaseDetailEntity>()
                .in(PurchaseDetailEntity::getStatus, Arrays.asList(WareConstant.PurchaseDetailStatusEnum.assigned.getCode()
                        , WareConstant.PurchaseDetailStatusEnum.created.getCode()))
                .in(PurchaseDetailEntity::getId, Arrays.asList(items)));
        if (count <= 0) {
            throw new RRException("不是新建和已分配的采购需求不能进行合并");
        }
        List<PurchaseDetailEntity> purchaseDetailEntities = Arrays.stream(items)
                .map(item -> {
                    PurchaseDetailEntity purchaseDetailEntity = new PurchaseDetailEntity();
                    purchaseDetailEntity.setPurchaseId(finalPurchaseId);
                    purchaseDetailEntity.setId(item);
                    purchaseDetailEntity.setStatus(WareConstant.PurchaseDetailStatusEnum.assigned.getCode());
                    return purchaseDetailEntity;
                }).collect(Collectors.toList());
        purchaseDetailService.updateBatchById(purchaseDetailEntities);


        PurchaseEntity purchaseEntity = new PurchaseEntity();
        purchaseEntity.setId(purchaseId);
        purchaseEntity.setUpdateTime(new Date());
        this.updateById(purchaseEntity);
    }

    @Override
    @Transactional
    public void received(Long[] purchase) {
        List<PurchaseEntity> purchaseEntities = this.list(new LambdaQueryWrapper<PurchaseEntity>()
                .in(PurchaseEntity::getId, Arrays.asList(purchase)))
                .stream()
                .filter(purchaseEntity -> purchaseEntity.getStatus().equals(WareConstant.MergeStatusEnum.assigned.getCode()))
                .peek(purchaseEntity -> {
                    purchaseEntity.setStatus(WareConstant.MergeStatusEnum.receive.getCode());
                    purchaseEntity.setUpdateTime(new Date());
                }).collect(Collectors.toList());
        this.updateBatchById(purchaseEntities);
        List<Long> ids = purchaseEntities.stream().map(PurchaseEntity::getId).collect(Collectors.toList());
        purchaseDetailService.updateInfoByPurchaseId(ids);
    }

    @Override
    @Transactional
    public void done(PurchaseDoneDto purchaseDoneDto) {
        AtomicBoolean success = new AtomicBoolean(false);
        List<PurchaseDetailsDto> purchaseDetailsDtoList = purchaseDoneDto.getPurchaseDetailsDtoList();
        List<Long> ids = purchaseDetailsDtoList.stream().map(PurchaseDetailsDto::getId)
                .collect(Collectors.toList());
        List<PurchaseDetailEntity> purchaseDetailEntities = purchaseDetailService.list(new LambdaQueryWrapper<PurchaseDetailEntity>()
                .eq(PurchaseDetailEntity::getStatus, WareConstant.PurchaseDetailStatusEnum.buying.getCode())
                .in(PurchaseDetailEntity::getId, ids));
        if (purchaseDetailEntities.size() <= 0) {
            return;
        }
        Map<Long, PurchaseDetailsDto> purchaseDetailsDtoMap = purchaseDetailsDtoList.stream()
                .collect(Collectors.toMap(PurchaseDetailsDto::getId, purchaseDetailsDto -> purchaseDetailsDto));
        purchaseDetailEntities = purchaseDetailEntities.stream()
                .peek(purchaseDetailEntity -> {
                    Long id = purchaseDetailEntity.getId();
                    PurchaseDetailsDto purchaseDetailsDto = purchaseDetailsDtoMap.get(id);
                    BeanUtils.copyProperties(purchaseDetailsDto, purchaseDetailEntity);
                    Integer status = purchaseDetailEntity.getStatus();
                    if (WareConstant.PurchaseDetailStatusEnum.error.getCode().equals(status)) {
                        success.set(false);
                        //保存库存
                    } else {
                        Integer skuNum = purchaseDetailEntity.getSkuNum();
                        PurchaseDetailEntity detailEntity = purchaseDetailService.getById(id);
                        Long wareId = detailEntity.getWareId();
                        Long skuId = detailEntity.getSkuId();
                        WareSkuEntity wareSkuEntity = wareSkuService.getOne(new LambdaQueryWrapper<WareSkuEntity>()
                                .eq(WareSkuEntity::getWareId, wareId)
                                .eq(WareSkuEntity::getSkuId, skuId));
                        if (wareSkuEntity == null) {
                            wareSkuEntity = new WareSkuEntity();
                            wareSkuEntity.setSkuId(skuId);
                            wareSkuEntity.setWareId(wareId);
                            wareSkuEntity.setStock(skuNum);
                            wareSkuEntity.setStockLocked(0);
                            try {
                                R info = productFeignService.info(skuId);
                                if (R.isOk(info)) {
                                    Map<String, Object> skuInfo = (Map<String, Object>) info.get("skuInfo");
                                    String skuName = (String) skuInfo.get("skuName");
                                    wareSkuEntity.setSkuName(skuName);
                                }
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        } else {
                            Integer stock = wareSkuEntity.getStock();

                            wareSkuEntity.setStock(stock + skuNum);
                        }
                        wareSkuService.saveOrUpdate(wareSkuEntity);
                    }
                }).collect(Collectors.toList());
        purchaseDetailService.updateBatchById(purchaseDetailEntities);
        Long purchaseId = purchaseDoneDto.getPurchaseId();
        PurchaseEntity purchaseEntity = new PurchaseEntity();
        purchaseEntity.setId(purchaseId);
        if (success.get()) {
            purchaseEntity.setStatus(WareConstant.MergeStatusEnum.finish.getCode());
        } else {
            purchaseEntity.setStatus(WareConstant.MergeStatusEnum.error.getCode());
        }
        this.updateById(purchaseEntity);

    }

}